﻿/*******************************************************************************************************************************************
Modification History:
********************************************************************************************************************************************
Date		Author		    Description
********************************************************************************************************************************************
05/07/2011	Brian Kuhn	    Created WeakAction class
*******************************************************************************************************************************************/
using System;

namespace Concise
{
    /// <summary>
    /// Represents a weak reference to an <see cref="Action{T}"/> which references a target object 
    /// while still allowing the target to be reclaimed by garbage collection.
    /// </summary>
    /// <typeparam name="T">The type of parameter passed to the <see cref="Action{T}"/> delegate.</typeparam>
    public class WeakAction<T> : WeakAction, IDeferredExecute
    {
        //=======================================================================================================
        //	Constructors
        //=======================================================================================================
        #region WeakAction(object target, Action<T> method)
        /// <summary>
        /// Initializes a new instance of the <see cref="WeakAction{T}"/> class 
        /// using the specified target and action.
        /// </summary>
        /// <param name="target">The object that can hold a reference to the <paramref name="method"/>.</param>
        /// <param name="method">A method that has a single parameter and does not return a value.</param>
        public WeakAction(object target, Action<T> method) : base(target, null)
        {
            _weakActionMethod   = method;
        }
        #endregion

        //=======================================================================================================
        //	Public Properties
        //=======================================================================================================
        #region Method
        /// <summary>
        /// Gets the delegate method referenced by this weak action.
        /// </summary>
        /// <value>
        /// The method that has a single parameter and does not return a value 
        /// that is referenced by the current <see cref="WeakAction{T}"/> object.
        /// </value>
        public new Action<T> Method
        {
            get
            {
                return _weakActionMethod;
            }
        }
        private readonly Action<T> _weakActionMethod;
        #endregion

        //=======================================================================================================
        //	Public Methods
        //=======================================================================================================
        #region Execute()
        /// <summary>
        /// Executes the delegate method referenced by this weak action using the 
        /// default value of the type <typeparamref name="T"/>.
        /// </summary>
        /// <remarks>
        /// The <see cref="Method"/> will only be executed if the referenced target object has not been garbage collected.
        /// </remarks>
        public new void Execute()
        {
            if (_weakActionMethod != null && this.IsAlive)
            {
                _weakActionMethod(default(T));
            }
        }
        #endregion

        #region Execute(T parameter)
        /// <summary>
        /// Executes the delegate method referenced by this weak action using the 
        /// specified <paramref name="parameter"/>.
        /// </summary>
        /// <param name="parameter">The parameter of type <typeparamref name="T"/> passed to the <see cref="Method"/>.</param>
        /// <remarks>
        /// The <see cref="Method"/> will only be executed if the referenced target object has not been garbage collected.
        /// </remarks>
        public void Execute(T parameter)
        {
            if (_weakActionMethod != null && this.IsAlive)
            {
                _weakActionMethod(parameter);
            }
        }
        #endregion

        //=======================================================================================================
        //	IDeferredExecute Implementation
        //=======================================================================================================
        #region Execute(params object[] parameters)
        /// <summary>
        /// Executes the delegate method using the specified <paramref name="parameters"/>.
        /// </summary>
        /// <param name="parameters">The parameters passed to the <see cref="Action{T}"/>.</param>
        /// <remarks>
        /// The first parameter is cast to the type of <typeparamref name="T"/>, and if 
        /// the first parameter cannot be cast; the <see langword="default"/> of <typeparamref name="T"/> 
        /// is passed instead.
        /// </remarks>
        public void Execute(params object[] parameters)
        {
            T value = default(T);
            try
            {
                value = (T)parameters[0];
            }
            catch (InvalidCastException)
            {
                value = default(T);
            }

            this.Execute(value);
        }
        #endregion
    }

    /// <summary>
    /// Represents a weak reference to an <see cref="Action{T, T2}"/> which references a target object 
    /// while still allowing the target to be reclaimed by garbage collection.
    /// </summary>
    /// <typeparam name="T">The first type of parameter passed to the <see cref="Action{T, T2}"/> delegate.</typeparam>
    /// <typeparam name="T2">The second type of parameter passed to the <see cref="Action{T, T2}"/> delegate.</typeparam>
    public class WeakAction<T, T2> : WeakAction, IDeferredExecute
    {
        //=======================================================================================================
        //	Constructors
        //=======================================================================================================
        #region WeakAction(object target, Action<T, T2> method)
        /// <summary>
        /// Initializes a new instance of the <see cref="WeakAction{T, T2}"/> class 
        /// using the specified target and action.
        /// </summary>
        /// <param name="target">The object that can hold a reference to the <paramref name="method"/>.</param>
        /// <param name="method">A method that has a two parameters and does not return a value.</param>
        public WeakAction(object target, Action<T, T2> method) : base(target, null)
        {
            _weakActionMethod = method;
        }
        #endregion

        //=======================================================================================================
        //	Public Properties
        //=======================================================================================================
        #region Method
        /// <summary>
        /// Gets the delegate method referenced by this weak action.
        /// </summary>
        /// <value>
        /// The method that has a two parameters and does not return a value 
        /// that is referenced by the current <see cref="WeakAction{T, T2}"/> object.
        /// </value>
        public new Action<T, T2> Method
        {
            get
            {
                return _weakActionMethod;
            }
        }
        private readonly Action<T, T2> _weakActionMethod;
        #endregion

        //=======================================================================================================
        //	Public Methods
        //=======================================================================================================
        #region Execute()
        /// <summary>
        /// Executes the delegate method referenced by this weak action using the 
        /// default value of the <typeparamref name="T"/> and <typeparamref name="T2"/> types.
        /// </summary>
        /// <remarks>
        /// The <see cref="Method"/> will only be executed if the referenced target object has not been garbage collected.
        /// </remarks>
        public new void Execute()
        {
            if (_weakActionMethod != null && this.IsAlive)
            {
                _weakActionMethod(default(T), default(T2));
            }
        }
        #endregion

        #region Execute(T first, T2 second)
        /// <summary>
        /// Executes the delegate method referenced by this weak action using the 
        /// specified parameters.
        /// </summary>
        /// <param name="first">The parameter of type <typeparamref name="T"/> passed to the <see cref="Method"/>.</param>
        /// <param name="second">The parameter of type <typeparamref name="T2"/> passed to the <see cref="Method"/>.</param>
        /// <remarks>
        /// The <see cref="Method"/> will only be executed if the referenced target object has not been garbage collected.
        /// </remarks>
        public void Execute(T first, T2 second)
        {
            if (_weakActionMethod != null && this.IsAlive)
            {
                _weakActionMethod(first, second);
            }
        }
        #endregion

        //=======================================================================================================
        //	IDeferredExecute Implementation
        //=======================================================================================================
        #region Execute(params object[] parameters)
        /// <summary>
        /// Executes the delegate method using the specified <paramref name="parameters"/>.
        /// </summary>
        /// <param name="parameters">The parameters passed to the <see cref="Action{T, T2}"/>.</param>
        /// <remarks>
        /// <para>
        /// The first parameter is cast to the type of <typeparamref name="T"/>, and if 
        /// the first parameter cannot be cast; the <see langword="default"/> of <typeparamref name="T"/> 
        /// is passed instead.
        /// </para>
        /// <para>
        /// The second parameter is cast to the type of <typeparamref name="T2"/>, and if 
        /// the second parameter cannot be cast; the <see langword="default"/> of <typeparamref name="T2"/> 
        /// is passed instead.
        /// </para>
        /// </remarks>
        public void Execute(params object[] parameters)
        {
            T value1    = default(T);
            try
            {
                value1  = (T)parameters[0];
            }
            catch (InvalidCastException)
            {
                value1  = default(T);
            }

            T2 value2   = default(T2);
            try
            {
                value2  = (T2)parameters[1];
            }
            catch (InvalidCastException)
            {
                value2  = default(T2);
            }

            this.Execute(value1, value2);
        }
        #endregion
    }
}
